package dk.pun.aot.client.presenter;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasWidgets;

import dk.pun.aot.client.AlphaOmegaToolsServiceAsync;
import dk.pun.aot.client.event.CharacterDeletedEvent;
import dk.pun.aot.client.event.CharacterSelectedEvent;
import dk.pun.aot.client.view.SelectCharacterView;
import dk.pun.aot.shared.character.CharacterData;
import dk.pun.aot.shared.character.CharacterId;
import dk.pun.aot.shared.user.UserData;

public class SelectCharacterPresenter implements Presenter, dk.pun.aot.client.view.SelectCharacterView.Presenter {

	private final UserData userData;
	private final AlphaOmegaToolsServiceAsync rpcService;
	private final HandlerManager eventBus;
	private SelectCharacterView view;

	public SelectCharacterPresenter(UserData userData, AlphaOmegaToolsServiceAsync rpcService, HandlerManager eventBus, SelectCharacterView view) {
		this.userData = userData;
		this.rpcService = rpcService;
		this.eventBus = eventBus;
		this.view = view;
		this.view.setPresenter(this);
	}
	
	@Override
	public void onCharacterSelected(final CharacterId selectedCharacterId) {
		this.userData.setSelectedCharacterId(selectedCharacterId);
		this.rpcService.updateUserData(this.userData, new AsyncCallback<Void>() {

			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failed to set selected character: ", caught);
			}

			@Override
			public void onSuccess(Void result) {
				eventBus.fireEvent(new CharacterSelectedEvent(selectedCharacterId));
				view.setSelectedCharacter(selectedCharacterId);
			}
		});
	}

	@Override
	public void onCharacterAdded(String name) {
		this.rpcService.createCharacterData(name, new AsyncCallback<CharacterData>() {

			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failed to add character: ", caught);
			}

			@Override
			public void onSuccess(CharacterData result) {
				CharacterId characterId = new CharacterId(result.getKey(), result.getName());
				userData.addCharacterId(characterId);
				onCharacterSelected(characterId);
				setCharactersInView();
			}
		});
	}

	@Override
	public void onCharacterRenamed(final CharacterId characterId) {
		this.userData.updateCharacterId(characterId);
		this.rpcService.updateUserData(this.userData, new AsyncCallback<Void>() {

			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failed to update user data: ", caught);
			}

			@Override
			public void onSuccess(Void result) {
				if (characterId.equals(userData.getSelectedCharacterId())) {
					eventBus.fireEvent(new CharacterSelectedEvent(characterId));
					view.setSelectedCharacter(characterId);
				}
				setCharactersInView();
			}
		});
		this.rpcService.getCharacterData(characterId.getKey(), new AsyncCallback<CharacterData>() {

			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failed to update character data: ", caught);
			}

			@Override
			public void onSuccess(CharacterData result) {
				result.setName(characterId.getName());
				rpcService.updateCharacterData(result, new AsyncCallback<Void>() {
					
					@Override
					public void onFailure(Throwable caught) {
						GWT.log("Failed to update character data: ", caught);
					}
					
					@Override
					public void onSuccess(Void result) {
					}
				});
			}
		});
	}

	@Override
	public void onCharacterDeleted(final CharacterId characterId) {
		if (this.userData.removeCharacterId(characterId)) {
			view.clearCharacterSelection();
			this.rpcService.updateUserData(this.userData, new AsyncCallback<Void>() {

				@Override
				public void onFailure(Throwable caught) {
					GWT.log("Failed to clear selected character: ", caught);
				}

				@Override
				public void onSuccess(Void result) {
					eventBus.fireEvent(new CharacterSelectedEvent(null));
				}
			});
		}
		
		this.rpcService.deleteCharacterData(characterId.getKey(), new AsyncCallback<Void>() {

			@Override
			public void onFailure(Throwable caught) {
				GWT.log("Failed to delete character: ", caught);
			}

			@Override
			public void onSuccess(Void result) {
				eventBus.fireEvent(new CharacterDeletedEvent(characterId));
				setCharactersInView();
			}
		});
	}

	@Override
	public void go(HasWidgets container) {
		container.clear();
		container.add(this.view.asWidget());

		this.setCharactersInView();
	}

	private void setCharactersInView() {
		this.view.setCharacters(userData.getCharacterIdIterator());
		this.view.setSelectedCharacter(userData.getSelectedCharacterId());
	}
}
